package cppcloud

import (
	"encoding/json"
	"fmt"
	"strings"
	"tool"
)

type CloudConf struct {
	app *CloudApp

	mainConfName string
	filesData    map[string]interface{} // 存放文件名->文件内容（json）
}

// createCloudConf 创建分布式配置客户端实例
func createCloudConf(app *CloudApp, listfname ...string) (cnf *CloudConf, err string) {
	cnf = &CloudConf{app: app, filesData: make(map[string]interface{})}
	var thisHandle MessageHandle = cnf
	for _, fname := range listfname {
		reqJson := map[string]interface{}{"file_pattern": fname, "incbase": 1}
		rspMap, errNo := app.RequestMap(CMD_GETCONFIG_REQ, reqJson)
		if 0 != errNo || nil == rspMap {
			fmt.Println("request config fail", errNo)
			return nil, "request config fail"
		}

		if retCode, ok := tool.JSONGetInt(rspMap, "code"); ok && 0 == retCode {
			cnf.setFile(rspMap)
			app.RequestMap(CMD_BOOKCFGCHANGE_REQ, reqJson)
		} else {
			fmt.Printf("CONFGETFAIL| rspMap=%v\n", rspMap)
		}
	}

	cnf.mainConfName = app.mconf // 当前主配置文件名
	app.SetCMDHandler(CMD_GETCONFIG_RSP, 0, &thisHandle, false)
	app.AddNotifyCallBack("cfg_change", cnf.notifyCallBack)

	return cnf, ""
}

func (cnf *CloudConf) setFile(data map[string]interface{}) {
	if fname, ok := tool.JSONGetString(data, "file_pattern"); ok {
		cnf.filesData[fname] = data
	}
}

func (cnf *CloudConf) getMTime(fname string) int {
	if jsonFile, ok := cnf.filesData[fname]; ok {
		mtime, _ := tool.JSONGetInt(jsonFile, "mtime")
		return mtime
	}
	return 0
}

// QueryValue 查询配置方法
// 输入：qkey 查询字符串，格式，filename/key1/key2/key3...
// 返回：查询到的在配置文件中的值；不存在时返回nil
func (cnf *CloudConf) QueryValue(qkey string, defval interface{}) (ret interface{}) {
	ret = defval

	keyArr := strings.Split(qkey, "/")
	filename := cnf.mainConfName
	if fstr := keyArr[0]; "" != fstr {
		filename = fstr
		keyArr = keyArr[1:]
	}

	param := []interface{}{filename, "contents"}
	for _, key := range keyArr {
		param = append(param, key)
	}

	if val := tool.JSONGetValue(cnf.filesData, param...); nil != val {
		ret = val
	} else {
		fmt.Println("NOCONF|", filename, keyArr)
	}

	return
}

// ProcessMessage 处理CMD_GETCONFIG_RSP响应消息（onConfResponse）
func (cnf *CloudConf) ProcessMessage(errCode int, cmdid, seqid uint16, bodystr string) *MessageData {
	rspMap := make(map[string]interface{})
	if nil == json.Unmarshal([]byte(bodystr), &rspMap) {
		code, codeOk := tool.JSONGetInt(rspMap, "code")
		contents := tool.JSONGetValue(rspMap, "contents")
		if codeOk && 0 == code && nil != contents {
			cnf.setFile(rspMap)
		}
	}

	return nil
}

func (cnf *CloudConf) notifyCallBack(msg map[string]interface{}) (code int, result interface{}) {
	filename, _ := tool.JSONGetString(msg, "filename")
	oMtime := cnf.getMTime(filename)
	mtime, ok := tool.JSONGetInt(msg, "mtime")

	if ok && mtime > oMtime {
		cnf.app.RequestNoWait(CMD_GETCONFIG_REQ,
			map[string]interface{}{"file_pattern": filename, "incbase": 1})
	}

	return
}
